﻿using System;
using System.Runtime.InteropServices;

namespace Ast.Core.Services.Extensions
{
    public class LocalMemoryBlock : IDisposable
    {
        public int Size { get; set; }
        public IntPtr Address { get; set; }

        public static LocalMemoryBlock Allocate(int size)
        {
            return new LocalMemoryBlock
            {
                Size = size,
                Address = Marshal.AllocHGlobal(size)
            };
        }
        public static LocalMemoryBlock Allocate<T>()
        {
            var size = Marshal.SizeOf<T>();
            return Allocate(size);
        }

        public LocalMemoryBlock Resize(int size)
        {
            Address = Marshal.ReAllocHGlobal(Address, new IntPtr(size));
            Size = size;
            return this;
        }

        public IntPtr ReadAsIntPtr()
        {
            return Marshal.ReadIntPtr(Address);
        }

        public int ReadAsInt32()
        {
            return Marshal.ReadInt32(Address);
        }

        public long ReadAsInt64()
        {
            return Marshal.ReadInt64(Address);
        }

        public byte ReadAsByte()
        {
            return Marshal.ReadByte(Address);
        }

        public byte[] ReadAsBytes()
        {
            return ReadAsBytes(Size, 0);
        }

        public byte[] ReadAsBytes(int length, int offset)
        {
            var bytes = new byte[length];
            Marshal.Copy(Address + offset, bytes, 0, length);
            return bytes;
        }

        public T ReadAs<T>()
        {
            return Marshal.PtrToStructure<T>(Address);
        }

        public void Dispose()
        {
            if (Address != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(Address);
            }
        }
    }
}